from rikapycli.Result import Result
from typing import Dict, List, Callable

from rikapycli.Utils import format_doc


class CommandManager(object):
    def __init__(self) -> None:
        self.command_name = 'base'
        self.sub_commands: Dict[str, CommandManager] = {}
        self.commands: Dict[str, Callable] = {}
        self._cache_commands()

    def _cache_commands(self) -> None:
        """缓存命令到`commands`变量
        """

        for name in dir(self):
            if not name.startswith("CMD_"):
                continue
            member = self.__getattribute__(name)
            if callable(member):
                self.commands[name[4:]] = member

    def add_sub_command(self, command_manager: 'CommandManager', as_name: str = ''):
        """ 添加子命令

        Args:

        - command_manager:

            子命令类实例

        """
        name = as_name if as_name else command_manager.command_name

        if name in self.sub_commands:
            raise Exception(f"重复的子命令: {name}")
        self.sub_commands[name] = command_manager

    def run(self, command_list: List[str]) -> Result:
        """ 运行命令并返回结果。

        Args:

        - command_list

            命令链，假设要调用 cp 命令，那么调用方式如下：

            >>> .run(['cp','./source.txt','./target.txt'])
        """
        name = command_list[0]
        if len(command_list) == 1:
            args = []
        else:
            args = command_list[1:]

        if name in self.sub_commands:
            if len(args) == 0:
                return self.call()
            return self.sub_commands[name].run(args)
        if name in self.commands:
            return self.commands[name](args)

        return Result(code=-1, message=f"没有指令 {command_list[0]}")

    def get_doc(self) -> str:
        """ 返回当前命令的帮助信息
        """
        return ''

    def get_command_doc(self, command: str) -> str:
        """获取某个命令的文档"""
        if command in self.sub_commands:
            return self.sub_commands[command].get_doc()
        if command in self.commands:
            func = self.commands[command]
            result = func.__doc__
            if isinstance(result, str):
                return format_doc(result)
        return ''

    def get_all_command_doc(self) -> str:
        """ 获取全部命令的帮助文档
        """
        result: List[str] = []

        for cmd in self.commands:
            result.append(f"- {cmd}\n" + self.get_command_doc(cmd))

        return '\n'.join(result)

    def call(self) -> Result:
        return self.CMD_help([])

    def CMD_help(self, args: List[str]) -> Result:
        """查看帮助"""
        doc = self.get_doc()
        cmd_doc = self.get_all_command_doc()

        return Result(message=f"{doc}\n--------------------\n{cmd_doc}")
